﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace QuailDashboard.View.Web
{
    public partial class LoadTestPage : System.Web.UI.Page
    {
        protected enum DisplayFormat
        {
            DayByDay,
            TestByTest,
        }

        private readonly QuailDataService _svc = new QuailDataService();
        protected string _group = "Js";
        protected int _environmentId = 33;
        protected DisplayFormat _format = DisplayFormat.DayByDay;
        protected DateTime _startDate = DateTime.Today.AddDays(-7), _endDate = DateTime.Today.AddDays(1);
        protected int _numTests;
        protected int _numThreads;

        public string PageTitle { get; set; }

        public override void Dispose()
        {
            _svc.Dispose();
            base.Dispose();
        }

        protected void Page_Load(object sender, EventArgs e)
        {

            if (!string.IsNullOrEmpty(Request.QueryString["group"]))
                _group = Request.QueryString["group"];

            if (!string.IsNullOrEmpty(Request.QueryString["env"]))
            {
                var env = _svc.GetEnvironment(Request.QueryString["env"]);
                if (env != null)
                    _environmentId = env.TestEnvironmentId;
            }

            if (!string.IsNullOrEmpty(Request.QueryString["daily"]))
                _format = DisplayFormat.DayByDay;
            else if (!string.IsNullOrEmpty(Request.QueryString["bytests"]))
                _format = DisplayFormat.TestByTest;

            DateTime dt;
            if (!string.IsNullOrEmpty(Request.QueryString["start"]) &&
                DateTime.TryParse(Request.QueryString["start"], out dt))
                _startDate = dt;
            if (!string.IsNullOrEmpty(Request.QueryString["end"]) &&
                DateTime.TryParse(Request.QueryString["end"], out dt))
                _endDate = dt;

            if (!string.IsNullOrEmpty(Request.QueryString["testsandthreads"]))
            {
                var testsAndThreads = Request.QueryString["testsandthreads"].Split('_');
                if (testsAndThreads.Length == 2)
                {
                    _numTests = Convert.ToInt32(testsAndThreads[0]);
                    _numThreads = Convert.ToInt32(testsAndThreads[1]);
                }
            }
        }

        public void WriteData()
        {
            var data = _svc.GetLoadTestRuns(_group, null, _environmentId, _startDate, _endDate, _numTests, _numThreads);

            if (_format == DisplayFormat.DayByDay)
                WriteDayByDay(data);

            else
                WriteTestByTest(data);

        }

        private void WriteTestByTest(IEnumerable<LoadTestRunData> data)
        {
            Response.Write("data.addColumn('string', 'Date/Time');\n");

            var outpt = data
                .Where(d => d.StartTime >= _startDate && d.StartTime < _endDate)
                .GroupBy(d => new
                                  {
                                      d.Url,
                                      StartTime = d.StartTime.ToString("MM/dd HH:mm:ss")
                                  },
                         d => d,
                         (u, ds) =>
                             {
                                 var all = ds.SelectMany(ltrd => ltrd.Details.Where(d => d.StatusCode == 200)).ToList();
                                 //var min = all.Any() ? all.Min(d => d.MsTotal) : int.MinValue;
                                 //var max = all.Any() ? all.Max(d => d.MsTotal) : int.MaxValue;
                                 return new
                                            {
                                                u.Url,
                                                u.StartTime,
                                                Times = all
                                                //.Where(d => d.MsTotal > min)
                                                //.Where(d => d.MsTotal < max)
                                            };
                             })
                .Where(u => u.Times.Any())
                .ToList();

            var urls = outpt
                .Select(o => o.Url)
                .Distinct()
                .ToList();

            urls
                .ForEach(u => Response.Write(string.Format("data.addColumn('number', '{0}');\n", u)));

            // find the distinct days

            var dates = outpt
                .Select(o => o.StartTime)
                .Distinct()
                .OrderBy(o => o)
                .ToList();

            Response.Write(string.Format("data.addRows({0});\n", dates.Count));

            // write the dates
            dates
                .ForEach(
                    (dt, i) =>
                    Response.Write(string.Format("data.setValue({0}, 0, '{1}');\n", i, dt)));

            // write the page data
            outpt
                .ForEach(o =>
                             {
                                 var urlidx = urls.IndexOf(o.Url);
                                 var dtidx = dates.IndexOf(o.StartTime);

                                 Response.Write(string.Format(
                                     "data.setValue({0}, {1}, {2});\n", dtidx,
                                     urlidx + 1,
                                     Math.Round(o.Times.Average(lt => lt.MsTotal)).ToString("0")));
                             });
        }

        private void WriteDayByDay(IEnumerable<LoadTestRunData> data)
        {
            Response.Write("data.addColumn('string', 'Date');\n");

            var outpt = data
                .Where(d => d.StartTime >= _startDate && d.StartTime < _endDate)
                .GroupBy(d => d.Url, d => d.Details,
                         (u, ds) =>
                             {
                                 var all = ds.SelectMany(lds => lds.Select(ltd => ltd)).ToList();
                                 return new
                                            {
                                                Url = u,
                                                Times = all
                                            };
                             })
                .ToList();

            outpt
                .ForEach(u => Response.Write(string.Format("data.addColumn('number', '{0}');\n", u.Url)));

            // find the distinct days

            var dates = outpt
                .SelectMany(o => o.Times.Select(p => p.StartTime.Date))
                .Distinct()
                .ToList();

            Response.Write(string.Format("data.addRows({0});\n", dates.Count));

            // write the dates
            dates
                .ForEach(
                    (dt, i) =>
                    Response.Write(string.Format("data.setValue({0}, 0, '{1}');\n", i, dt.ToString("MM/dd"))));

            // write the page data
            outpt
                .ForEach((url, urlidx) => url.Times
                                              .GroupBy(ltd => ltd.StartTime.Date)
                                              .ForEach(ltd =>
                                                           {
                                                               var dtidx = dates.IndexOf(ltd.Key);
                                                               Response.Write(string.Format(
                                                                   "data.setValue({0}, {1}, {2});\n", dtidx,
                                                                   urlidx + 1,
                                                                   ltd.Average(lt => lt.MsTotal)));
                                                           }));
        }

        protected string GetStartDate()
        {
            return _startDate.ToString();
        }

        protected string GetEndDate()
        {
            return _endDate.ToString();
        }

        protected string GetTestsAndThreadsOptions()
        {
            var testsAndThreads = _svc.GetTestsAndThreads();
            return "<option value=\"\">All</option>"
                   +
                   testsAndThreads.Select(
                       tt =>
                       "<option value=\"" + tt.Item1 + "_" + tt.Item2 + "\">" + tt.Item1 + " /" + tt.Item2 + "</option>")
                       .JoinStrings("\n");
        }

        protected string GetTestsAndThreadsPerGroup()
        {
            var testsAndThreadsPerGroup = _svc.GetTestsAndThreadsByGroup();
            return "{"
                   + testsAndThreadsPerGroup.Select(ttg => "\"" + ttg.Key + "\": ["
                                                           +
                                                           ttg.Value.Select(
                                                               tt => "\"" + tt.Item1 + "_" + tt.Item2 + "\"").
                                                               JoinStrings(", ")
                                                           + "]").JoinStrings(", ")
                   + "}";
        }

        protected string GetTestAndThreadsValue()
        {
            if (_numThreads == 0 || _numTests == 0)
                return "";
            return _numTests + "_" + _numThreads;
        }

        protected string GetEnvironmentSelectOptions()
        {
            return _svc.GetEnvironments()
                .OrderBy(te => te.EnvironmentName)
                .Select(te => "<option value=\"" + HttpUtility.HtmlEncode(te.EnvironmentName) + "\""
                              + (_environmentId == te.TestEnvironmentId ? " selected" : string.Empty)
                              + ">" + HttpUtility.HtmlEncode(te.EnvironmentName) + "</option>")
                .JoinStrings("\n");
        }

        protected string GetDataGroupOptions()
        {
            return _svc.GetLoadTestGroups()
                .Select(ltg => "<option value=\"" + HttpUtility.HtmlEncode(ltg) + "\""
                              + (_group == ltg ? " selected" : string.Empty)
                              + ">" + HttpUtility.HtmlEncode(ltg) + "</option>")
                .JoinStrings("\n");            
        }
    }
}